<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <!DOCTYPE html>
    <html lang="zh-CN">

    <head>
        <meta charset="UTF-8">
        <title>外凸波峰圆环动画</title>
        <style>
            html,
            body {
                margin: 0;
                background: #111;
                height: 100%;
                display: flex;
                justify-content: center;
                align-items: center
            }

            canvas {
                border-radius: 8px
            }
        </style>
    </head>

    <body>
        <canvas id="c" width="600" height="600"></canvas>
        <script>
            /* ========== 单个外凸波峰 ========== */
            class Bump {
                constructor(center, amp, width, cycles) {
                    this.center = center;   // 弧度
                    this.amp = amp;      // 最大振幅
                    this.width = width;    // 弧度宽度
                    this.maxCycles = cycles;
                    this.cycles = cycles;   // 剩余起伏次数
                    this.phase = 0;
                }
                /* 仅外凸的当前振幅（随 cycles 递减到 0）*/
                currentAmp() {
                    return this.amp * Math.abs(Math.cos(this.phase)) * (this.cycles / this.maxCycles);
                }
                /* 每帧更新，返回 true 表示完成 */
                update() {
                    this.phase += 0.05;          // 起伏速度
                    if (this.phase >= Math.PI * 2) {
                        this.phase = 0;
                        this.cycles--;
                    }
                    return this.cycles <= 0;
                }
            }

            /* ========== 圆环波管理 ========== */
            class RingWave {
                constructor(cx, cy, baseR) {
                    this.cx = cx;
                    this.cy = cy;
                    this.baseR = baseR;
                    this.bumps = [];
                }
                /* 随机添加 1 个外凸波峰 */
                addRandomBump() {
                    const center = Math.random() * Math.PI * 2;
                    const amp = 25 + Math.random() * 25;   // 25~50
                    const width = 0.05 + Math.random() * 0.1; // 0.3~0.6 rad
                    const cycles = 1 ; // 3~6 次起伏
                    this.bumps.push(new Bump(center, amp, width, cycles));
                }
                /* 每帧更新并绘制 */
                updateAndDraw(ctx) {
                    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
                    ctx.beginPath();
                    const pts = 360;
                    for (let i = 0; i <= pts; i++) {
                        const angle = (i / pts) * Math.PI * 2;
                        let pulse = 0;
                        /* 叠加所有外凸波峰 */
                        this.bumps.forEach(b => {
                            const dist = Math.abs(angle - b.center);
                            const wrap = Math.min(dist, Math.PI * 2 - dist);
                            if (wrap < b.width) {
                                const shape = Math.abs(Math.cos(wrap / b.width * Math.PI / 2));
                                pulse += shape * b.currentAmp();
                            }
                        });
                        const r = this.baseR + pulse;
                        const x = this.cx + Math.cos(angle) * r;
                        const y = this.cy + Math.sin(angle) * r;
                        i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
                    }
                    ctx.closePath();
                    ctx.strokeStyle = '#0ff';
                    ctx.lineWidth = 2.5;
                    ctx.stroke();
                    ctx.fillStyle = 'rgba(0,255,255,0.08)';
                    ctx.fill();
                    /* 清理已完成波峰 */
                    this.bumps = this.bumps.filter(b => !b.update());
                }
            }

            /* ========== 主程序 ========== */
            const cvs = document.getElementById('c');
            const ctx = cvs.getContext('2d');
            const ring = new RingWave(300, 300, 150);

            function loop() {
                ring.updateAndDraw(ctx);
                requestAnimationFrame(loop);
            }
            loop();

            /* 每隔 1~2 秒随机添加 1~3 个波峰 */
            setInterval(() => {
                const count = 1 + Math.floor(Math.random() * 3);
                for (let i = 0; i < count; i++) ring.addRandomBump();
            },50);
        </script>
    </body>

    </html>
    </script>
</body>

</html>